
// #include "hal_display.h"
#include "codec_interface.h"
#include "audio_manager.h"

#include <algorithm>
#include <cstring>
#include <fstream>
#include <iostream>
#include <sstream>

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>

using namespace std;

int main(int argc, char **argv)
{
    int ret;

    struct AudioManager *audioManager = GetAudioManagerFuncs();
    if (audioManager == NULL)
        printf("\n----->> GetAudioManagerFuncs: failed\n");

    // 获取音频驱动中支持的所有适配器的列表
    struct AudioAdapterDescriptor *descs = NULL;
    int descsSize = 0;

    ret = audioManager->GetAllAdapters(audioManager, &descs, &descsSize);
    printf("\n----->> audioManager->GetAllAdapters(%d)\n", ret);

    // 遍历列表,定位到录音、播音适配器
    struct AudioAdapterDescriptor *descIn = NULL;
    struct AudioAdapterDescriptor *descOut = NULL;

    for (int i = 0; i < descsSize; i++)
    {
        printf("  descName: %s, portNum %d\n",
            descs[i].adapterName, descs[i].portNum);
    
        for (int j = 0; j < descs[i].portNum; j++)
        {
            printf("    %d: dir %d, id 0x%X, portName %s \n", j,
            descs[i].ports[j].dir,
            descs[i].ports[j].portId,
            descs[i].ports[j].portName);

            if (descs[i].ports[j].dir == PORT_IN)
                descIn = &descs[i];
            else if (descs[i].ports[j].dir == PORT_OUT)
                descOut = &descs[i];
            else if (descs[i].ports[j].dir == PORT_OUT_IN)
                ; // 这种既能播音又能录音的不知道怎么用...
        }
    }

    // 根据 AudioAdapterDescriptor 获得 AudioAdapter
    struct AudioAdapter *adapterIn = NULL;
    struct AudioAdapter *adapterOut = NULL;

    if (descIn)
    {
        ret = audioManager->LoadAdapter(audioManager, descIn, &adapterIn);
        printf("\n----->> audioManager->LoadAdapter(%d) descIn\n", ret);
    }
    if (descOut)
    {
        ret = audioManager->LoadAdapter(audioManager, descOut, &adapterOut);
        printf("\n----->> audioManager->LoadAdapter(%d) descOut\n", ret);
    }

    // AudioAdapter 自身初始化
    ret = adapterIn->InitAllPorts(adapterIn);
    printf("\n----->> adapterIn->InitAllPorts(%d) adapterIn\n", ret);

    ret = adapterOut->InitAllPorts(adapterOut);
    printf("\n----->> adapterOut->InitAllPorts(%d) adapterOut\n", ret);

    //创建录音 AudioCapture 和播音 AudioRender
    struct AudioRender *render = NULL;
    struct AudioDeviceDescriptor addOut;
    addOut.portId = descOut->ports[0].portId;
    struct AudioSampleAttributes asaOut;
    asaOut.type = AUDIO_IN_MEDIA;
    asaOut.interleaved = 0;
    asaOut.format = AUDIO_FORMAT_PCM_16_BIT;
    asaOut.sampleRate = 16000;
    asaOut.channelCount = 1;
    ret = adapterOut->CreateRender(adapterOut, &addOut, &asaOut, &render);
    printf("\n----->> adapterOut->CreateRender(%d) adapterOut\n", ret);
    printf("  AudioDeviceDescriptor: portId/%d, pins/%d, desc/%s \n",
        addOut.portId, addOut.pins, addOut.desc);
    printf("  AudioSampleAttributes: type/%d, interleaved/%d, format/%d, sampleRate/%d, channelCount/%d\n",
        asaOut.type, asaOut.interleaved, asaOut.format, asaOut.sampleRate, asaOut.channelCount);

    struct AudioCapture *capture = NULL;
    struct AudioDeviceDescriptor addIn;
    addIn.portId = descIn->ports[0].portId;
    struct AudioSampleAttributes asaIn;
    asaIn.type = AUDIO_IN_MEDIA;
    asaIn.interleaved = 0;
    asaIn.format = AUDIO_FORMAT_PCM_16_BIT;
    asaIn.sampleRate = 16000;
    asaIn.channelCount = 1;
    ret = adapterIn->CreateCapture(adapterIn, &addIn, &asaIn, &capture);
    printf("\n----->> adapterIn->CreateCapture(%d) adapterIn\n", ret);
    printf("  AudioDeviceDescriptor: portId/%d, pins/%d, desc/%s \n",
        addIn.portId, addIn.pins, addIn.desc);
    printf("  AudioSampleAttributes: type/%d, interleaved/%d, format/%d, sampleRate/%d, channelCount/%d\n",
        asaIn.type, asaIn.interleaved, asaIn.format, asaIn.sampleRate, asaIn.channelCount);

    // 释放
    if (adapterOut && render)
    {
        ret = adapterOut->DestroyRender(adapterOut, render);
        printf("\n----->> adapterOut->DestroyRender(%d)\n", ret);
    }
    if (adapterIn && capture)
    {
        ret = adapterIn->DestroyCapture(adapterIn, capture);
        printf("\n----->> adapterIn->DestroyCapture(%d)\n", ret);
    }

    if (adapterIn)
        audioManager->UnloadAdapter(audioManager, adapterIn);
    if (adapterOut)
        audioManager->UnloadAdapter(audioManager, adapterOut);

#if 0

    int fd = open(argv[1], O_RDONLY);
    printf("\n----->> open(%d): %s \n", fd, argv[1]);

    /////////////////////////////

    // ret = HalPlayerSysInit();
    // printf("\n----->> HalPlayerSysInit(%d) \n", ret);

    ret = CodecInit();
    printf("\n----->> CodecInit(%d) \n", ret);

    const char *audioEncName = "codec.aac.hardware.encoder";
    CODEC_HANDLETYPE handle = NULL;

    Param param[10];
    int index = 0;

    AvCodecMime codecMime_ = MEDIA_MIMETYPE_AUDIO_AAC;
    param[index].key = KEY_MIMETYPE;
    param[index].val = &codecMime_;
    param[index++].size = sizeof(AvCodecMime);
    
    CodecType domainKind_ = AUDIO_ENCODER;
    param[index].key = KEY_CODEC_TYPE;
    param[index].val = &domainKind_;
    param[index++].size = sizeof(CodecType);
    
    // uint32_t profile_ = 0x1000;
    // param[index].key = KEY_AUDIO_PROFILE;
    // param[index].val = &profile_;
    // param[index++].size = sizeof(uint32_t);
    
    uint32_t sampleRate_ = 16000;
    param[index].key = KEY_SAMPLE_RATE;
    param[index].val = &sampleRate_;
    param[index++].size = sizeof(uint32_t);
    
    uint32_t bitRate_ = 32000;
    param[index].key = KEY_BITRATE;
    param[index].val = &bitRate_;
    param[index++].size = sizeof(uint32_t);
    
    AudioSoundMode soundMode_ = AUD_SOUND_MODE_MONO;
    param[index].key = KEY_SOUND_MODE;
    param[index].val = &soundMode_;
    param[index++].size = sizeof(AudioSoundMode);
    
    uint32_t ptNumPerFrm_ = 1024;
    param[index].key = KEY_POINT_NUM_PER_FRAME;
    param[index].val = &ptNumPerFrm_;
    param[index++].size = sizeof(uint32_t);
    
    // uint32_t bufSize_ = 30;
    // param[index].key = KEY_BUFFERSIZE;
    // param[index].val = &bufSize_;
    // param[index++].size = sizeof(uint32_t);

    ///////////////////////

    // AvCodecMime mime = MEDIA_MIMETYPE_VIDEO_HEVC;
    // param[index].key = KEY_MIMETYPE;
    // param[index].val = (void *)&mime;
    // param[index++].size = sizeof(AvCodecMime);
    
    // uint32_t width = 1920;
    // param[index].key = KEY_WIDTH;
    // param[index].val = (void *)&width;
    // param[index++].size = sizeof(uint32_t);
    
    // uint32_t height = 1080;
    // param[index].key = KEY_HEIGHT;
    // param[index].val = (void *)&height;
    // param[index++].size = sizeof(uint32_t);
    
    // uint32_t bufSize = 0;
    // param[index].key = KEY_BUFFERSIZE;
    // param[index].val = (void *)&bufSize;
    // param[index++].size = sizeof(uint32_t);
    
    // CodecType domain = VIDEO_DECODER;
    // param[index].key = KEY_CODEC_TYPE;
    // param[index].val = (void *)&domain;
    // param[index++].size = sizeof(CodecType);
    
    ret = CodecCreate(audioEncName, param, index, &handle);
    printf("\n----->> CodecCreate(%d) \n", ret);

    sleep(1);

    if (handle != NULL)
    {
        ret = CodecDestroy(handle);
        printf("\n----->> CodecDestroy(%d) \n", ret);

        ret = CodecDeinit();
        printf("\n----->> CodecDeinit(%d) \n", ret);
    }

#endif

    return 0;
}
